package mx.com.sinformex.chat.core.server.impl;

import java.io.IOException;


import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

import mx.com.sinformex.chat.core.Manager;
import mx.com.sinformex.chat.core.client.IChatClient;
import mx.com.sinformex.chat.core.client.impl.ChatClient;
import mx.com.sinformex.chat.core.server.IChatRoom;
import mx.com.sinformex.chat.core.server.IChatServer;
import mx.com.sinformex.chat.core.server.ServiceThreadfactory;

/**
 * @author Oscar Ivan Hernandez Ventura [ oscar at sinformex dot com dot mx]
 *
 * @version $ Id : XmlServer.java , v 1.0 Aug 13, 2009 angellore $
 */
public class XmlServer implements IChatServer {

	private Manager manager = null;
	private int port = 1024;//You need to ser a upper port via application context file
	private boolean run = false;
	private ServerSocket server;
	private final Log log = LogFactory.getLog(getClass());
	private Map<String, IChatRoom> rooms = new HashMap<String,IChatRoom>();
	private Class<?> chatClassInstance = ChatRoom.class;//The detault class for any chat
	private ExecutorService requestPool;
	
	public XmlServer() {
		requestPool = Executors.newFixedThreadPool(10, new ServiceThreadfactory("xml-server"));
	}
	
	public void start() {
		try {
			server = new ServerSocket(port);
			run = true;
			log.info(String.format("Accepting connections in port %d", port));
			
			if(rooms.size() == 0) {
				log.info(String.format("Not custom rooms configured; creating default one of type %s", chatClassInstance.getName()));
				IChatRoom room = (IChatRoom) chatClassInstance.newInstance();
				rooms.put("default", room);
			} else {
				
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public void stop() {
		run = false;
	}

	public void run() {
		if(manager == null) {
			throw new IllegalStateException("This server needs a Manager instance.");
		}
		
		while(run) {
			try {
				Socket client = server.accept();
				client.setSoTimeout(1000 * 30);
				
				ChatClient cc = new ChatClient(client, this);
				
				requestPool.execute(cc);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void setManager(Manager manager) {
		this.manager = manager;
	}
	
	public Manager getManager() {
		return manager;
	}
	
	@Required
	public void setPort(String port) {
		this.port = Integer.parseInt(port);
	}

	public void setRooms(List<String> rooms) {
		//TODO implement this method
	}

	public void joinToRoom(IChatClient client, String roomName) {
		IChatRoom room = rooms.get(roomName);
		if(room == null) {
			log.error(String.format("The room %s does not exist.", roomName));
			return;
		}
		
		room.joinClient(client);
	}

	public void removeToRoom(IChatClient client, String roomName) {
		IChatRoom room = rooms.get(roomName);
		if(room == null) {
			log.error(String.format("The room %s does not exist.", roomName));
			return;
		}
		
		room.removeClient(client);
	}

	public List<IChatRoom> getRooms() {
		return new ArrayList<IChatRoom>(rooms.values());
	}

}
